#pragma once
#define CONTACTS_IP "127.0.0.1"
#define CONTACTS_PORT 8888
#include <iostream>
#include <string>
#include "request.pb.h"
#include "../../cpp-httplib/httplib.h"
#include "ContactException.h"
#include "response.pb.h"
class ContactClinet
{
private:
    // 构建请求
    void buildAddRequest(request::AddContactRequest *req_ptr)
    {
        std::cout << "请输入联系人姓名：";
        std::string name;
        getline(std::cin, name);
        req_ptr->set_name(name);
        std::cout << "请输入联系人年龄：";
        int32_t age;
        std::cin >> age;
        std::cin.ignore(256, '\n');
        req_ptr->set_age(age);
        // 添加电话
        for (int i = 1;; i++)
        {
            std::cout << "请输⼊联系⼈电话" << i << "(只输⼊回⻋完成电话新增): ";
            std::string number;
            getline(std::cin, number);
            if (number.empty())
            {
                break;
            }
            request::Phone *phone = req_ptr->add_phones();
            phone->set_number(number);
            std::cout << "选择此电话类型 (1、移动电话 2、固定电话) : ";
            int type;
            std::cin >> type;
            std::cin.ignore(256, '\n');
            switch (type)
            {
            case 1:
                phone->set_type(request::Phone_PhoneType::Phone_PhoneType_MP);
                break;
            case 2:
                phone->set_type(request::Phone_PhoneType::Phone_PhoneType_TEL);
                break;
            default:
                std::cout << "----⾮法选择，使⽤默认值！" << std::endl;
                break;
            }
        }
        // 添加性别
        std::cout << " 请输入联系人性别：(1.male  2.female)：";
        int male = 0;
        std::cin >> male;
        std::cin.ignore(256, '\n');
        if (male == 1)
        {
            std::string male = "male";
            req_ptr->set_male(male);
        }
        else if (male == 2)
        {
            std::string female = "female";
            req_ptr->set_female(female);
        }
        else
        {
            std::cout << " 非法选择，设置为默认值！" << std::endl;
        }
        // 添加备注
        for (int i = 1;; i++)
        {
            std::cout << "请输⼊备注" << i << "标题 (只输⼊回⻋完成备注新增): ";
            std::string remark_key;
            getline(std::cin, remark_key);
            if (remark_key.empty())
            {
                break;
            }
            std::cout << "请输⼊备注" << i << "内容: ";
            std::string remark_value;
            getline(std::cin, remark_value);
            req_ptr->mutable_remarks()->insert({remark_key, remark_value});
        }
    }
    void printFindAllContactsResponse(response::FindAllContactsResponse &rep)
    {
        if (rep.contacts().size() == 0)
        {
            std::cout << "-------还没有添加联系人-------" << std::endl;
            return;
        }
        for (auto &contact : rep.contacts())
        {
            std::cout << "联系人姓名：" << contact.name() << " 联系人ID：" << contact.uid() << std::endl;
        }
    }
    void printFindoneContactsResponse(response::FindOneContactResponse &rep)
    {
        std::cout << "联系人姓名：" << rep.name() << std::endl;
        std::cout << "联系人ID：" << rep.uid() << std::endl;
        std::cout << "联系人年龄：" << rep.age() << std::endl;
        switch (rep.gender_case())
        {
        case response::FindOneContactResponse::kMale:
            std::cout << "联系人性别：male" << std::endl;
            break;
        case response::FindOneContactResponse::kFemale:
            std::cout << "联系人性别：female" << std::endl;
            break;
        case response::FindOneContactResponse::GENDER_NOT_SET:
            std::cout << "联系人性别未设置" << std::endl;
            break;
        default:
            std::cout << "----未知错误----" << std::endl;
            break;
        }
        for (auto &phone : rep.phones())
        {
            int j = 1;
            std::cout << "电话" << j++ << ": " << phone.number();
            std::cout << " (" << phone.PhoneType_Name(phone.type()) << ")" << std::endl;
        }
        // 打印备注
        if (rep.marks_size())
        {
            std::cout << "备注信息: " << std::endl;
        }
        for (auto it = rep.marks().cbegin(); it != rep.marks().cend(); ++it)
        {
            std::cout << " " << it->first << ": " << it->second << std::endl;
        }
    }

public:
    ContactClinet() {}
    ~ContactClinet() {}

    // 添加联系人
    void addContact()
    {
        httplib::Client cli(CONTACTS_IP, CONTACTS_PORT);
        // 构建请求
        request::AddContactRequest req;
        buildAddRequest(&req);

        // 将请求序列化
        std::string req_str;
        if (!req.SerializePartialToString(&req_str))
        {
            throw ContactException("addContact: 反序列化失败！");
        }
        // 发送Post请求
        auto res = cli.Post("/contacts/add", req_str, "application/protobuf");
        if (!res)
        {
            std::string err_desc;
            err_desc.append("addContact: Post err: ")
                .append(std::to_string(res.error()));
            throw ContactException(err_desc);
        }

        // 将结果反序列化
        response::AddContactResponse rep;
        bool parse = rep.ParseFromString(res->body);
        if (res->status != 200 && !parse)
        {
            // 通过httplib的response获取错误信息
            std::string err_desc;
            err_desc.append("addContact: post '/contacts/add/' 失败：")
                .append(std::to_string(res->status))
                .append("(")
                .append(res->reason)
                .append(")");
            throw ContactException(err_desc);
        }
        else if (res->status != 200)
        {
            // 服务端异常
            std::string err_desc;
            err_desc.append("addContacts: post '/contacts/add/' 失败 ")
                .append(std::to_string(res->status))
                .append("(")
                .append(res->reason)
                .append(") 错误原因：")
                .append(rep.base().err_desc());
            throw ContactException(err_desc);
        }
        else if (!rep.base().success())
        {
            // 结果异常
            std::string err_desc;
            err_desc.append("addContact: post '/contacts/add/' 结果异常：")
                .append("异常原因：")
                .append(rep.base().err_desc());
            throw ContactException(err_desc);
        }

        std::cout << "-------新增联系人成功-------" << std::endl;
        std::cout << "新增联系人ID：" << rep.uid() << std::endl;
    }
    // 删除联系人
    void delContact()
    {
        httplib::Client cli(CONTACTS_IP, CONTACTS_PORT);
        // 构建请求
        request::DelContactRequest req;
        std::cout << "请输入需要删除联系人的uid: ";
        std::string uid;
        getline(std::cin, uid);
        req.set_uid(uid);

        // 将请求序列化
        std::string req_str;
        if (!req.SerializePartialToString(&req_str))
        {
            throw ContactException("delContact: 反序列化失败！");
        }
        // 发送Post请求
        auto res = cli.Post("/contacts/del", req_str, "application/protobuf");
        if (!res)
        {
            std::string err_desc;
            err_desc.append("delContact: Post err: ")
                .append(std::to_string(res.error()));
            throw ContactException(err_desc);
        }

        // 将结果反序列化
        response::DelContactRequest rep;
        bool parse = rep.ParseFromString(res->body);
        if (res->status != 200 && !parse)
        {
            // 通过httplib的response获取错误信息
            std::string err_desc;
            err_desc.append("delContact: post '/contacts/del/' 失败：")
                .append(std::to_string(res->status))
                .append("(")
                .append(res->reason)
                .append(")");
            throw ContactException(err_desc);
        }
        else if (res->status != 200)
        {
            // 服务端异常
            std::string err_desc;
            err_desc.append("delContacts: post '/contacts/del/' 失败 ")
                .append(std::to_string(res->status))
                .append("(")
                .append(res->reason)
                .append(") 错误原因：")
                .append(rep.base().err_desc());
            throw ContactException(err_desc);
        }
        else if (!rep.base().success())
        {
            // 结果异常
            std::string err_desc;
            err_desc.append("post '/contacts/del/ 结果异常：")
                .append("异常原因：")
                .append(rep.base().err_desc());
            throw ContactException(err_desc);
        }

        std::cout << "-------删除联系人成功-------" << std::endl;
        std::cout << "删除联系人ID：" << rep.uid() << std::endl;
    }
    // 查找联系人
    void findContact()
    {
        httplib::Client cli(CONTACTS_IP, CONTACTS_PORT);
        request::FindOneContactRequest req;
        std::cout << "输入需要查询的id: ";
        std::string uid;
        getline(std::cin, uid);
        req.set_uid(uid);
        // 序列化请求
        std::string req_str;
        if (!req.SerializeToString(&req_str))
        {
            throw ContactException("findContact：序列化失败");
        }
        auto res = cli.Post("/contacts/find-all", req_str, "application/protobuf");
        if (!res)
        {
            std::string err_desc;
            err_desc.append("findContact: /contacts/find-one 链接错误！错误信息：")
                .append(std::to_string(res.error()));
            throw ContactException(err_desc);
        }
        // 反序列化响应
        response::FindOneContactResponse rep;
        bool parse = rep.ParseFromString(res->body);
        // 处理异常
        if (res->status != 200 && !parse)
        {
            std::string err_desc;
            err_desc.append("findContact: post '/contacts/find-one' 失败：")
                .append(std::to_string(res->status))
                .append("(")
                .append(res->reason)
                .append(")");
            throw ContactException(err_desc);
        }
        else if (res->status != 200)
        {
            std::string err_desc;
            err_desc.append("post '/contacts/find-one' 失败 ")
                .append(std::to_string(res->status))
                .append("(")
                .append(res->reason)
                .append(") 错误原因：")
                .append(rep.base().err_desc());
            throw ContactException(err_desc);
        }
        else if (!rep.base().success())
        {
            // 结果异常
            std::string err_desc;
            err_desc.append("findContact: post '/contacts/find-one' 结果异常：")
                .append("异常原因：")
                .append(rep.base().err_desc());
            throw ContactException(err_desc);
        }
        std::cout << "-------查找联系人成功-------" << std::endl;
        std::cout << "联系人uid: " << rep.uid() << std::endl;
        printFindoneContactsResponse(rep);
    }
    // 查找通讯录
    void findContacts()
    {
        httplib::Client cli(CONTACTS_IP, CONTACTS_PORT);
        auto res = cli.Get("/contacts/find-all");
        if (!res)
        {
            std::string err_desc;
            err_desc.append("findContacts: /contacts/find-all 链接错误！错误信息：")
                .append(std::to_string(res.error()));
            throw ContactException(err_desc);
        }
        // 反序列化response
        response::FindAllContactsResponse rep;
        bool parse = rep.ParseFromString(res->body);
        if (res->status != 200 && !parse)
        {
            std::string err_desc;
            err_desc.append("findContacts: get '/contacts/find-all' 失败：")
                .append(std::to_string(res->status))
                .append("(")
                .append(res->reason)
                .append(")");
            throw ContactException(err_desc);
        }
        else if (res->status != 200)
        {
            // 服务端异常
            std::string err_desc;
            err_desc.append("post '/contacts/find-all' 失败 ")
                .append(std::to_string(res->status))
                .append("(")
                .append(res->reason)
                .append(") 错误原因：")
                .append(rep.base().err_desc());
            throw ContactException(err_desc);
        }
        else if (!rep.base().success())
        {
            // 结果异常
            std::string err_desc;
            err_desc.append("findContacts: post '/contacts/find-all' 结果异常：")
                .append("异常原因：")
                .append(rep.base().err_desc());
            throw ContactException(err_desc);
        }
        // 正常返回，打印结果
        printFindAllContactsResponse(rep);
    }
};
